<?php

require __DIR__ . DIRECTORY_SEPARATOR . '../lib/User.php';
require __DIR__ . DIRECTORY_SEPARATOR . '../lib/Article.php';
require __DIR__ . DIRECTORY_SEPARATOR . '../lib/Db2.php';
require __DIR__ . DIRECTORY_SEPARATOR . '../lib/ErrorCode.php';

$pdo = Db2::getInstance();

class Restful
{
    private $_user; // 请求用户资源
    private $_article; // 请求文章资源
    private $_requestMethod; //请求方法
    private $_resourceName; //请求资源名称
    private $_resourceId; //请求资源ID
    private $_allowResources = ['users', 'articles']; // 允许请求的资源列表
    private $_allowRequestMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; // 允许请求的方法
    // 常用状态码
    private $_statusCodes = [
        200 => 'Ok',
        204 => 'No Content',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        403 => 'Forbidden',
        404 => 'Not found',
        405 => 'Method not Allowed',
        500 => 'Server Internal Error'
    ];

    /**
     * Restful constructor.
     * @param $_user
     * @param $_article
     */
    public function __construct($_user, $_article)
    {
        $this->_user = $_user;
        $this->_article = $_article;
    }

    public function run()
    {
        try {
            $this->_setupRequestMethod();
            $this->_setupResource();
            if ($this->_resourceName == 'users') {
                return $this->_json($this->_handleUsers());
            }
            if ($this->_resourceName == 'articles') {
                return $this->_json($this->_handleArticles());
            }
        } catch (Exception $e) {
            $this->_json(['error' => $e->getMessage()], $e->getCode());
        }
    }

    /**
     * 初始化请求方法
     */
    private function _setupRequestMethod()
    {
        $this->_requestMethod = $_SERVER['REQUEST_METHOD'];
        if (!in_array($this->_requestMethod, $this->_allowRequestMethods)) {
            throw new Exception('请求方法不被允许', 405);
        }
    }

    /**
     * 初始化请求资源
     */
    private function _setupResource()
    {
        $path = $_SERVER['REQUEST_URI'];
        $params = explode('/', $path);
        if (strpos($params[3], '?')) {
            $this->_resourceName = explode('?', $params[3])[0];
        } else {
            $this->_resourceName = $params[3];
        }

        if (!in_array($this->_resourceName, $this->_allowResources)) {
            throw new Exception('请求资源不被允许', 400);
        }
        if (!empty($params[4])) {
            $this->_resourceId = $params[4];
        }
    }

    /**
     * 输出json
     * @param array $array
     */
    private function _json($message, $code = 0)
    {
        if ($message === null && $code === 0) {
            $code = 204;
        }
        if ($message !== null && $code === 0) {
            $code = 200;
        }
        header("HTTP/1.1 {$code} {$this->_statusCodes[$code]}");
        header('Content-Type:application/json;charset=utf-8');
        if ($message !== null) {
            echo json_encode($message, JSON_UNESCAPED_UNICODE);
        }
        exit();
    }


    /**
     * 请求用户资源
     * @return 用户注册
     */
    private function _handleUsers()
    {
        if ($this->_requestMethod != 'POST') {
            throw new Exception('请求方法不被允许', 405);
        }
        $body = $this->_getBodyParams();
        if (empty($body['username'])) {
            throw new Exception('用户名不能为空', 400);
        }
        if (empty($body['password'])) {
            throw new Exception('密码不能为空', 400);
        }
        return $this->_user->register($body['username'], $body['password']);
    }

    /**
     * 请求文章资源
     */
    private function _handleArticles()
    {
        $method = $this->_requestMethod;
        switch ($method) {
            case 'POST':
                return $this->_handleArticleCreate();
                break;
            case 'PUT':
                return $this->_handleArticleEdit();
                break;
            case 'DELETE':
                return $this->_handleArticleDelete();
                break;
            case 'GET':
                if (empty($this->_resourceId)) {
                    return $this->_handleArticleLists();
                } else {
                    return $this->_handleArticleView();
                }
                break;
            default:
                throw new Exception('请求方法不被允许', 405);
        }
    }


    /**
     * 获取请求体，返回 JSON数组
     * @return false|string
     */
    private function _getBodyParams()
    {
        $raw = file_get_contents('php://input');
        if (empty($raw)) {
            throw new Exception('请求参数错误', 400);
        }
        return json_decode($raw, true);
    }


    /**
     * 新建文章
     * @return 文章
     */
    private function _handleArticleCreate()
    {
        $body = $this->_getBodyParams();
        if (empty($body['title'])) {
            throw  new  Exception('文章标题不能为空', 400);
        }
        if (empty($body['content'])) {
            throw  new  Exception('文章内容不能为空', 400);
        }

        $user = $this->_userLogin($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
        try {
            $article = $this->_article->create($body['title'], $body['content'], $user['user_id']);
            return $article;
        } catch (Exception $e) {
            $errCodes = [
                ErrorCode::ARTICLE_TITLE_CANNOT_EMPTY,
                ErrorCode::ARTICLE_CONTENT_CANNOT_EMPTY
            ];
            if (in_array($e->getCode(), $errCodes)) {
                throw new Exception($e->getMessage(), 400);
            }
            throw new Exception($e->getMessage(), 500);
        }
    }

    /**
     * 更新文章
     * @throws Exception
     */
    private function _handleArticleEdit()
    {
        $user = $this->_userLogin($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
        try {
            $article = $this->_article->view($this->_resourceId);
            if ($article['user_id'] != $user['user_id']) {
                throw new Exception('您无权编辑', 403);
            }
            $body = $this->_getBodyParams();
            $title = empty($body['title']) ? $article['title'] : $body['title'];
            $content = empty($body['content']) ? $article['content'] : $body['content'];
            if ($title == $article['title'] && $content == $article['content']) {
                return $article;
            }
            return $this->_article->edit($article['article_id'], $title, $content, $user['user_id']);
        } catch (Exception $e) {
            if ($e->getCode() < 100) {
                if ($e->getCode() == ErrorCode::ARTICLE_EMPTY) {
                    throw new Exception($e->getMessage(), 404);
                } else {
                    throw new Exception($e->getMessage(), 400);
                }
            } else {
                throw $e;
            }
        }
    }

    /**
     * 获取文章列表
     */
    private function _handleArticleLists()
    {
        $user = $this->_userLogin($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
        $page = isset($_GET['page']) ? $_GET['page'] : 1;
        $size = isset($_GET['size']) ? $_GET['size'] : 10;
        if ($size > 100) {
            throw new Exception('单页数量最为不超过100', 400);
        }
        return $this->_jsonResponse(
            'success', '成功', $this->_article->getList($user['user_id'], $page, $size));
    }

    /**
     * 文章信息
     */
    private function _handleArticleView()
    {
        try {
            $article = $this->_article->view($this->_resourceId);
            return $this->_jsonResponses('200','成功',$article);
        } catch (Exception $e) {
            if ($e->getCode() == ErrorCode::ARTICLE_EMPTY) {
                throw new Exception($e->getMessage(), 404);
            } else {
                throw new Exception($e->getMessage(), 500);
            }
        }

    }

    /**
     * 删除文章
     * @return null
     * @throws Exception
     */
    private function _handleArticleDelete()
    {
        $user = $this->_userLogin($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
        try {
            $article = $this->_article->view($this->_resourceId);
            if ($article['user_id'] != $user['user_id']) {
                throw new Exception('您无权删除', 403);
            }
            $this->_article->delete($article['article_id'], $user['user_id']);
            return null;
        } catch (Exception $e) {
            if ($e->getCode() < 100) {
                if ($e->getCode() == ErrorCode::ARTICLE_EMPTY) {
                    throw new Exception($e->getMessage(), 404);
                } else {
                    throw new Exception($e->getMessage(), 400);
                }
            } else {
                throw $e;
            }
        }
    }

    /**
     * 用户登录
     * @param $PHP_AUTH_USER
     * @param $PHP_AUTH_PW
     */
    private function _userLogin($PHP_AUTH_USER, $PHP_AUTH_PW)
    {
        try {
            return $this->_user->login($PHP_AUTH_USER, $PHP_AUTH_PW);
        } catch (Exception $e) {
            $errCodes = [
                ErrorCode::USERNAME_CANNOT_EMPTY,
                ErrorCode::PASSWORD_CANNOT_EMPTY,
                ErrorCode::USERNAME_OR_PASSWORD_INVALID
            ];
            if (in_array($e->getCode(), $errCodes)) {
                throw new Exception($e->getMessage(), 401);
            }
            throw new Exception($e->getMessage(), 500);
        }
    }

    private function _jsonResponses($code, $message, $data = [])
    {
        $content = [
            'code' => $code,
            'message' => $message,
            'data' => $data
        ];
        return json_encode($content,JSON_UNESCAPED_UNICODE);
        // 同时使用两个变量 = JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES = 256 + 64 = 320;
        // return json_encode($content,320);
    }

}

$article = new Article($pdo);
$user = new User($pdo);

$restful = new Restful($user, $article);
$restful->run();